#pragma once

#include "exchange.hpp"
#include "binding.hpp"
#include "messagequeue.hpp"
#include "message.hpp"

namespace mymq
{
    class VirtualHost
    {
    public:
        using ptr = std::shared_ptr<VirtualHost>;
    public:
        VirtualHost(const std::string& host, const std::string &basedir, const std::string &dbfile)
            : _host_name(host), _exchange(dbfile), _msgqueue(dbfile), _binding(dbfile), _message(basedir)
        {
            auto msgqueue_map = _msgqueue.GetAllMsgQueue();
            for (const auto &msgqueue : msgqueue_map)
            {
                _message.InitQueueMessage(msgqueue.first);
            }
        }
        bool DeclareExchange(const std::string &name, mymq::ExchangeType type,
                             bool durable, bool auto_delete,
                             const google::protobuf::Map<std::string, std::string> &args)
        {
            return _exchange.DeclareExchange(name, type, durable, auto_delete, args);
        }
        bool DeleteExchange(const std::string &name)
        {
            // 删除交换机的时候，需要将交换机相关的绑定信息也删除掉
            _binding.RemoveExchangeBindings(name);
            return _exchange.DeleteExchange(name);
        }
        bool ExistsExchange(const std::string &name)
        {
            return _exchange.Exists(name);
        }
        Exchange::ptr SelectExchange(const std::string& ename)
        {
            return _exchange.SelectExhcange(ename);
        }
        bool DeclareQueue(const std::string &name, bool durable, bool exclusive, bool auto_delete,
                          const google::protobuf::Map<std::string, std::string> &args)
        {
            // 初始化队列的消息句柄（消息的存储管理）
            _message.InitQueueMessage(name);
            return _msgqueue.DeclareMsgQueue(name, durable, exclusive, auto_delete, args);
        }
        bool DeleteQueue(const std::string &name)
        {
            // 删除的时候队列相关的数据有两个：队列的消息，队列的绑定信息
            _binding.RemoveMsgQueueBindings(name);
            _message.DestoryQueueMessage(name);
            return _msgqueue.DeleteMsgQueue(name);
        }
        bool ExistsQueue(const std::string &name)
        {
            return _msgqueue.Exists(name);
        }
        std::vector<std::string> GetAllMsgQueue()
        {
            auto msgqueues = _msgqueue.GetAllMsgQueue();
            std::vector<std::string> res;
            for (const auto& msgqueue: msgqueues)
            {
                res.emplace_back(msgqueue.first);
            }
            return std::move(res);
        }
        bool Bind(const std::string &ename, const std::string &qname, const std::string &key)
        {
            Exchange::ptr exp = _exchange.SelectExhcange(ename);
            if (exp.get() == nullptr)
            {
                INFO_LOG("交换机与队列绑定失败，交换机%s不存在！", ename.c_str());
                return false;
            }
            MsgQueue::ptr mqp = _msgqueue.SelectMsgQueue(qname);
            if (mqp.get() == nullptr)
            {
                INFO_LOG("交换机与队列绑定失败，队列%s不存在！", qname.c_str());
                return false;
            }
            return _binding.Bind(ename, qname, key, exp->durable && mqp->durable);
        }
        bool UnBind(const std::string &ename, const std::string &qname)
        {
            return _binding.UnBind(ename, qname);
        }
        BindingMapper::MsgQueueBindingMap GetExchangeBindings(const std::string &name)
        {
            return _binding.GetExchangeBindings(name);
        }
        bool ExistsBinding(const std::string &ename, const std::string &qname)
        {
            return _binding.Exists(ename, qname);
        }
        bool Publish(const std::string &qname, BasicProperties *bp, const std::string &body)
        {
            MsgQueue::ptr mqp = _msgqueue.SelectMsgQueue(qname);
            if (mqp.get() == nullptr)
            {
                INFO_LOG("发布消息失败，队列%s不存在！", qname.c_str());
                return false;
            }
            return _message.Insert(qname, bp, body, mqp->durable);
        }
        MessagePtr Consume(const std::string &qname)
        {
            return _message.Front(qname);
        }
        bool Ack(const std::string &qname, const std::string &msg_id)
        {
            return _message.Ack(qname, msg_id);
        }
        void Clear()
        {
            _exchange.Clear();
            _msgqueue.Clear();
            _message.Clear();
            _binding.Clear();
        }

    private:
        std::string _host_name;
        ExchangeManager _exchange;
        MsgQueueManager _msgqueue;
        BindingManager _binding;
        MessageManager _message;
    };
}